package main

type Mutex struct {
	key  int32
	sema int32
}

func xadd(val *int32, delta int32) (new int32) {
	for {
		v := *val
		// cas这个函数是原子操作，它有三个参数，第一个是目标数据的地址，第二个是目标数据的旧值，第三个则是等待更新的新值。每次CAS都会用old和addr内的数据进行比较，如果数值相等，则执行操作，用new覆盖addr内的旧值，如果数据不相等，则忽略后面的操作。
		if cas(val, v, v+delta) {
			return v + delta
		}
	}
	panic("unreached")
}

func (m *Mutex) Lock() {
	if xadd(&m.key, 1) == 1 {
		// changed from 0 to 1; we hold lock
		return
	}
	// semacquire函数首先检查信号量是否为0：如果大于0，让信号量减一，返回； 
	// 如果等于0，就调用goparkunlock函数，把当前Goroutine放入该sema的等待队列，并把他设为等待状态。
	sys.semacquire(&m.sema)
}

func (m *Mutex) Unlock() {
	if xadd(&m.key, -1) == 0 {
		// changed from 1 to 0; no contention
		return
	}
	// semrelease函数首先让信号量加一，然后检查是否有正在等待的Goroutine： 如果没有，直接返回；
	// 如果有，调用goready函数唤醒一个Goroutine。
	sys.semrelease(&m.sema)
}
